'''
* This is the projet for Brtc LlmOps Platform
* @Author Leon-liao <liaosiliang@alltman.com>
* @Description //TODO 
* @File: document_schema.py
* @Time: 2025/11/12
* @All Rights Reserve By Brtc
'''
import uuid

from flask_wtf import FlaskForm
from marshmallow import Schema, fields, pre_dump
from wtforms import StringField, BooleanField
from wtforms.validators import DataRequired, Length, Optional, AnyOf

from internal.entity.dataset_entity import ProcessType, DEFAULT_PROCESS_RULE
from internal.exception.exception import ValidateErrorException
from internal.lib.helper import datetime_to_timestamp
from internal.model import Document
from internal.schema.schema import ListField, DictField
from pkg.paginator.paginator import PaginatorReq


class UpdateDocumentNameReq(FlaskForm):
    """更新文档名称/基础信息请求"""
    name = StringField("name", validators=[
        DataRequired("文档名称不能为空"),
        Length(max=100, message="文档的名称长度不能超过100")
    ])


class GetDocumentsWithPageReq(PaginatorReq):
    """获取文档分页列表请求"""
    search_word = StringField("search_word", default="", validators=[
        Optional()
    ])


class GetDocumentResp(Schema):
    """获取文档基础信息响应结构"""
    id = fields.UUID(dump_default="")
    dataset_id = fields.UUID(dump_default="")
    name = fields.String(dump_default="")
    segment_count = fields.Integer(dump_default=0)
    character_count = fields.Integer(dump_default=0)
    hit_count = fields.Integer(dump_default=0)
    position = fields.Integer(dump_default=0)
    enabled = fields.Bool(dump_default=False)
    disabled_at = fields.Integer(dump_default=0)
    status = fields.String(dump_default="")
    error = fields.String(dump_default="")
    updated_at = fields.Integer(dump_default=0)
    created_at = fields.Integer(dump_default=0)

    @pre_dump
    def process_data(self, data: Document, **kwargs):
        return {
            "id": data.id,
            "dataset_id": data.dataset_id,
            "name": data.name,
            "segment_count": data.segment_count,
            "character_count": data.character_count,
            "hit_count": data.hit_count,
            "position": data.position,
            "enabled": data.enabled,
            "disabled_at": datetime_to_timestamp(data.disabled_at),
            "status": data.status,
            "error": data.error,
            "updated_at": datetime_to_timestamp(data.updated_at),
            "created_at": datetime_to_timestamp(data.created_at),
        }


class GetDocumentsWithPageResp(Schema):
    """获取文档分页列表响应结构"""
    id = fields.UUID(dump_default="")
    name = fields.String(dump_default="")
    character_count = fields.Integer(dump_default=0)
    hit_count = fields.Integer(dump_default=0)
    position = fields.Integer(dump_default=0)
    enabled = fields.Bool(dump_default=False)
    disabled_at = fields.Integer(dump_default=0)
    status = fields.String(dump_default="")
    error = fields.String(dump_default="")
    updated_at = fields.Integer(dump_default=0)
    created_at = fields.Integer(dump_default=0)

    @pre_dump
    def process_data(self, data: Document, **kwargs):
        return {
            "id": data.id,
            "name": data.name,
            "character_count": data.character_count,
            "hit_count": data.hit_count,
            "position": data.position,
            "enabled": data.enabled,
            "disabled_at": datetime_to_timestamp(data.disabled_at),
            "status": data.status,
            "error": data.error,
            "updated_at": datetime_to_timestamp(data.updated_at),
            "created_at": datetime_to_timestamp(data.created_at),
        }

class CreateDocumentReq(FlaskForm):
    """创建文档的 请求数据校验"""
    upload_file_ids = ListField("upload_file_ids")
    process_type = StringField("process_type", validators=[
        DataRequired("文档分割器不能为空！！"),
        AnyOf(values=[ProcessType.AUTOMATIC, ProcessType.CUSTOM], message="处理类型格式错误！！"),
    ])
    rule = DictField("rule")

    # def validate_XXXX(变量名)
    def validate_upload_file_ids(self, field:ListField):
        """校验上传的文档列表"""
        #1、校验数据是否为空
        if not isinstance(field.data, list):
            raise ValidateErrorException("文件id列表格式必须是数组！")
        #2、校验数据的长度, 最多只能同时处理10个文档
        if len(field.data) == 0 or len(field.data) > 10:
            raise ValidateErrorException("新增文档数量在 1-10 之间")
        #3、循环校验 id 是否为 uuid
        for  up_id in field.data:
            try:
                uuid.UUID(up_id)
            except Exception as e:
                raise ValidateErrorException(f"文档id的格式必须是UUID")
        #4、删除重复的数据并能新
        field.data = list(dict.fromkeys(field.data))

    def validate_rule(self, field):
        """校验处理规则"""
        #1、检验处理模式，如果为自动，则rule为默认值
        if self.process_type.data == ProcessType.AUTOMATIC:
            field.data = DEFAULT_PROCESS_RULE["rule"]
        else:
            #2、检测 自定义处理去是否传了  rule
            if not isinstance(field.data, dict) or len(field.data) == 0:
                raise ValidateErrorException("自定义处理模式下， 必须携带rule 且不能为空！")
            #3、校验pre_process_rules,涵盖、非空、列表类型
            if "pre_process_rules" not in field.data or  not isinstance(field.data["pre_process_rules"], list):
                raise ValidateErrorException("pre_process_rules必须为列表")
            #4、提取 pre_process_rule中的唯一处理规则避免重复处理
            unique_pre_process_rule_dict = {}
            for pre_process_rule in field.data["pre_process_rules"]:
                #5、检验id参数
                if(
                    "id" not in pre_process_rule
                    or pre_process_rule["id"] not in ["remove_extra_space", "remove_url_and_email"]
                ):
                    raise ValidateErrorException("预处理的id 错误！！")

                #6、校验enable参数\涵盖：非空 布尔值
                if "enabled" not in pre_process_rule or not isinstance(pre_process_rule["enabled"], bool):
                    raise ValidateErrorException("预处理格式 enabled 错误")
                #7、将数据添加到唯一字典中
                unique_pre_process_rule_dict[pre_process_rule["id"]] = {
                    "id": pre_process_rule["id"],
                    "enabled": pre_process_rule["enabled"],
                }
            #8、判断一下是否传递的两个处理规则
            if len(unique_pre_process_rule_dict) != 2:
                raise ValidateErrorException("预处理格式应该包含  id  和  enabled！！！")
            #9、将处理后的数据转换成列表并覆盖与预处理
            field.data["pre_process_rules"] = list(unique_pre_process_rule_dict.values())
            #10、检验分段参数segment ，涵盖非空、字典
            if "segment"  not in field.data or not isinstance(field.data["segment"], dict):
                raise ValidateErrorException("segment必须为字典且非空！！")
            #11、校验分隔符separators, 涵盖非空、列表、子元素
            if "separators" not in field.data["segment"] or not isinstance(field.data["segment"]["separators"], list):
                raise ValidateErrorException("segment的'separators' 必须非空且为列表！！")
            for separator in field.data["segment"]["separators"]:
                if not isinstance(separator, str):
                    raise ValidateErrorException("segment 的 'separators' 元素错误")
            if len(field.data["segment"]["separators"]) == 0:
                raise ValidateErrorException("segment 'separators' 不能为空")
            #12、校验chunk_size 分块大小，涵盖非空 数字 范围
            if "chunk_size" not in field.data["segment"] or not isinstance(field.data["segment"]["chunk_size"], int):
                raise ValidateErrorException("segment 'chunk_size'必须为整数")
            if field.data["segment"]["chunk_size"] <= 100 or field.data["segment"]["chunk_size"] > 1000:
                raise ValidateErrorException("segment 'chunk_size'大小必须在 100 - 1000 之间")
            #13、检验块大小chunk_overlap， 涵盖非空、数字 、范围
            if (
                "chunk_overlap" not in field.data["segment"]
                or not isinstance(field.data["segment"]["chunk_overlap"], int)
            ):
                raise ValidateErrorException("segment 'chunk_overlap'必须存在且为整数！")

            if not (0<=field.data["segment"]["chunk_overlap"] <= field.data["segment"]["chunk_size"]*0.5):
                raise ValidateErrorException("segment 'chunk_overlap' 必须小 chunk_size 的0.5倍。")
            #14、组装数据
            field.data = {
                "pre_process_rules": field.data["pre_process_rules"],
                "segment": {
                    "separators": field.data["segment"]["separators"],
                    "chunk_size": field.data["segment"]["chunk_size"],
                    "chunk_overlap": field.data["segment"]["chunk_overlap"],
                }
            }

class CreateDocumentResp(Schema):
    """创建文档列表返回响应结构"""
    documents = fields.List(fields.Dict, dump_default=[])
    batch = fields.String(dump_default="")

    @pre_dump
    def process_data(self, data:tuple[list[Document], str], **kwargs):
        return {
            "documents":[{
                "id": document.id,
                "name":document.name,
                "status":document.status,
                "created_at":int(document.created_at.timestamp()),
            } for document in data[0]],
            "batch":data[1],
        }

class UpdateDocumentEnabledReq(FlaskForm):
    """更新文档启用状态请求"""
    enabled = BooleanField('enabled')

    def validate_enabled(self, field:BooleanField)->None:
        """校验文档启用状态"""
        if not isinstance(field.data, bool):
            raise ValidateErrorException("文档 enabled 状态不能为空 且 必须是 布尔值")

















